package com.example.luckybag.service

import android.accessibilityservice.AccessibilityService
import android.graphics.Rect
import android.util.Log
import android.view.accessibility.AccessibilityNodeInfo
import com.example.luckybag.utils.AccessibilityClick

/**
 * 文件名： <br/>
 * 描述：钉钉抢红包服务类
 * 🌝🌝🌝
 *
 * @author wulinran
 * @since 2023/2/10 10:01
 */
class DingTalkLuckyBagService(private val service: AccessibilityService) :
    LuckyBagService(service) {

    private val TAG = "DingTalkLuckyBagService"
    // 用于做限制的
    private var lastDingTalkSearch = 0L

    // 这两个是用于定位开红包按钮位置的view的id 为啥这样，后面会介绍
    private val dingTalkTvBlessWordId = "com.alibaba.android.rimet:id/tv_bless_word"
    private val dingTalkTvViewDetail = "com.alibaba.android.rimet:id/tv_view_detail"

    // 开红包页面
    private val dingTalkPChatPage =
        "com.alibaba.android.dingtalk.redpackets.activities.FestivalRedPacketsPickActivity"
    // 红包详情页面
    private val dingTalkPRedPacketPage =
        "com.alibaba.android.dingtalk.redpackets.activities.RedPacketsDetailActivity"


    override fun dealClassName(className: String,viewGet:ViewGet) {
        when (className) {
            // 聊天列表页面，用这俩是因为，没找到特殊的条件，吐槽下，钉钉咋还在用ListView,我猜是有米田共山🌝🌝🌝
            "android.widget.ListView",
            "android.widget.FrameLayout" -> {
                getLuckyBagCard(viewGet.getRootView())
            }

            // 红包弹框
            dingTalkPChatPage -> {
                openLuckyBag(viewGet)
            }

            // 红包详情页面
            dingTalkPRedPacketPage -> {
                closeLuckyBagDetail(viewGet.getRootView())
            }
        }
    }

    /**
     * 跟微信一样，获取所有的红包卡片，用于执行点击，不过这里只点击第一个能点的红包
     *
     * 聊天窗口中的红包都存在"查看红包"一词,因此可根据该词查找红包
     *
     * @param rootInActiveWindow 根部ViewNode
     */

    override fun getLuckyBagCard(rootInActiveWindow: AccessibilityNodeInfo?) {
        Log.e(TAG, "获取红包")
        val sys = System.currentTimeMillis()
        if (sys - lastDingTalkSearch < 1000) {
            return
        }
        lastDingTalkSearch = sys
        val caches: ArrayList<Any> = ArrayList()
        recycleDingTalk(rootInActiveWindow, caches)
        if (caches.isNotEmpty()) {
            for (index in 0 until caches.size) {
                if (caches[index] is AccessibilityNodeInfo && (index == caches.size - 1 || caches[index + 1] !is String)) {
                    val node = caches[index] as AccessibilityNodeInfo
                    var parent = node.parent
                    while (parent != null) {
                        if (parent.isClickable) {
                            parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                            Log.e("测试无障碍", "获取红包成功")
                            break
                        }
                        parent = parent.parent
                    }
                    break
                }
            }
        }
    }

    /**
     * 递归查找当前聊天窗口中的红包信息
     *
     * 整体逻辑跟微信是一样的，特殊字符串标记不能点的红包
     *
     * @param node 根node
     * @param caches 用于记录红包缓存的临时数据
     */

    private fun recycleDingTalk(node: AccessibilityNodeInfo?, caches: ArrayList<Any>) {
        if(null != node) {
            Log.e("测试无障碍id", "${node.viewIdResourceName} ${node.className}  ${node.text}")
            if (node.childCount == 0) {
                if (node.text != null) {

                    if ("查看红包" == node.text.toString()) {
                        caches.add(node)
                    }

                    if (node.text.toString().contains("已领取") || node.text.toString()
                            .contains("已过期")
                    ) {
                        caches.add("#")
                    }
                }
            } else {
                for (i in 0 until node.childCount) {
                    if (node.getChild(i) != null) {
                        recycleDingTalk(node.getChild(i), caches)
                    }
                }
            }
        }
    }

    /**
     * 递归查找当前聊天窗口中的红包信息
     *
     * 简单说下，这里跟微信的不一样，debug没有找到开红包按钮，也就是说这是空的，本人太菜，没找到原因，所以用了个间接方法
     * 获取附近两个view的位置，根据它们的值，以及目测的比例，来确定对应坐标，然后使用无障碍点击来实现
     * 开红包按钮的x坐标是跟第一个node一样的，所以开红包使用的是第一个的值，Y轴坐标就是通过上下两个node估算的，
     * 为了准确，使用了两个值，也就是在两个位置做了点击，提高容错率
     *
     * @param node 根node
     * @param caches 用于记录红包缓存的临时数据
     */

    override fun openLuckyBag(viewGet: ViewGet) {
        Log.e(TAG, "点击红包")
        Thread.sleep(100)
        val rootInActiveWindow = viewGet.getRootView()
        try {
            val des =
                rootInActiveWindow?.findAccessibilityNodeInfosByViewId(dingTalkTvBlessWordId)
            val rect = Rect()
            des?.get(0)?.getBoundsInScreen(rect)

            val detail =
                rootInActiveWindow?.findAccessibilityNodeInfosByViewId(dingTalkTvViewDetail)
            val detailR = Rect()
            detail?.get(0)?.getBoundsInScreen(detailR)

            val y = (rect.exactCenterY() + detailR.exactCenterY()) / 2 + 10
            val y2 = (rect.exactCenterY() + detailR.exactCenterY()) / 2 + 50

            // 这里为了防止位置不准  在两个地方加点击事件  提高下容错率
            AccessibilityClick.click(
                service,
                rect.exactCenterX(),
                y
            )

            AccessibilityClick.click(
                service,
                rect.exactCenterX(),
                y2
            )
        } catch (e: Throwable) {
            Log.e(TAG + "_openDingTalkPacket_error", e.printStackTrace().toString())
        }
    }

    /**
     * 关闭红包详情
     *
     * 一样，匹配特殊字段，间接拿到对应按钮，做点击，当然也可以通过id获取目标node
     *
     * @param node 根rootInActiveWindow
     */

    override fun closeLuckyBagDetail(node: AccessibilityNodeInfo?) {
        val list = node?.findAccessibilityNodeInfosByText("钉钉红包")
        if (list?.isNotEmpty() == true) {
            val parent = list[0].parent
            if (parent != null) {
                for (j in 0 until parent.childCount) {
                    val child = parent.getChild(j)
                    if (child != null && child.isClickable) {
                        child.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                    }
                }

            }

        }
    }
}